package com.fattyCorps.battle.service.battle.behavior;

import cn.hutool.extra.spring.SpringUtil;
import com.fattyCorps.battle.service.battle.Battle;
import com.fattyCorps.battle.service.battle.data.BattleHero;
import com.fattyCorps.common.enums.battle.EBehaviorType;
import com.fattyCorps.common.enums.battle.triggerCondition.EBehaviorCondition;
import com.fattyCorps.common.mgr.Cfg;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 行为处理器
 * 一次时机的触发，会制造出多个行为
 */
@Slf4j
public class BhvProcessor {

    @Data
    public static class Event implements Comparable {
        // 条件
        EBehaviorCondition cnd;
        // 条件的发起者
        BattleHero trigger = null;
        // 上个事件发生时有互斥事件类型，本次事件无法触发相关类型
        List<EBehaviorType> counterBhvTypes = new ArrayList<>();

        // todo: 这种需要实现排序接口的队列有问题，后面找个其它队列
        @Override
        public int compareTo(Object o) {
            return 0;
        }
    }

    // 时机队列
    Queue<Event> cnds = new PriorityQueue<>();
    boolean running = false;
    // 某个行为触发后，不能再触发的事件类型
    List<EBehaviorType> counterBhvTypes = new ArrayList<>();
    // 某次事件中产生的有效的行为
    Set<Behavior> activeEventBhvs = new HashSet<>();
    Battle battle;
    Cfg cfg;
    boolean over = false;

    // 行为目标管理器
    // 保存某个事件触发后，其所有行为筛选出的目标
    public class BhvTarget {
        private HashMap<Behavior, List<BattleHero>> bhvTargetHeroes = new HashMap<>();

        public void addAll(Behavior bhv, List<BattleHero> heroes) {
            List<BattleHero> orgHeroes = bhvTargetHeroes.get(bhv);
            if (orgHeroes == null) {
                orgHeroes = new ArrayList<>();
            }

            orgHeroes.addAll(heroes);
            bhvTargetHeroes.put(bhv, orgHeroes);
        }

        public void clear() {
            bhvTargetHeroes.clear();
        }

        public List<BattleHero> getTargets(Integer bhvId) {
            Iterator<Map.Entry<Behavior, List<BattleHero>>> iterator = bhvTargetHeroes.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Behavior, List<BattleHero>> next = iterator.next();
                if (next.getKey().getMould().getId() == bhvId) {
                    return next.getValue();
                }
            }

            return null;
        }

        public List<BattleHero> getTargets(Behavior bhv) {
            return bhvTargetHeroes.get(bhv);
        }
    }

    @Getter
    private BhvTarget bhvTarget = new BhvTarget();

    public BhvProcessor(Battle battle) {
        this.battle = battle;
        cfg = SpringUtil.getBean(Cfg.class);
    }

    public void onEvent(EBehaviorCondition cnd) {
        onEvent(cnd, null);
    }

    // 有可能出现触发一个事件时，其结果会导致再触发其它事件，这些都属于同一个事件内一起处理
    public void onEvent(EBehaviorCondition cnd, BattleHero caster) {
        if (over) {
            return;
        }

        Event e = new Event();
        e.setCnd(cnd);
        e.setTrigger(caster);
        e.getCounterBhvTypes().addAll(this.counterBhvTypes);

        cnds.offer(e);

        if (!running) {
            running = true;
            run();
            running = false;
        }
    }

    public void addCounterBhvType(EBehaviorType type) {
        if (type.equals(EBehaviorType.None)) {
            return;
        }

        counterBhvTypes.add(type);
    }

    public void clearCounter() {
        this.counterBhvTypes.clear();
    }

    public static boolean isCounterBhv(Behavior bhv, List<EBehaviorType> counterBhvTypes) {
        for (EBehaviorType counterBhvType : counterBhvTypes) {
            if (bhv.getMould().getType().equals(counterBhvType)) {
                return true;
            }
        }

        return false;
    }

    public void activeBehavior(Behavior behavior) {
        activeEventBhvs.add(behavior);
    }

    public void over() {
        cnds.clear();
        over = true;
    }

    private void run() {
        Event e = cnds.poll();
        if (e != null) {
            triggerEvent(e);
            run();
        }
    }

    // 触发一个事件
    private void triggerEvent(Event e) {
        if (e.getTrigger() != null && e.getTrigger().isDead()) {
            // todo: 身上有死亡后触发的行为需要做特殊处理
            // 暂时处理为死亡就不触发任何自己身上的行为了
            return;
        }

        battle.getRecorder().newEvent(e.getCnd(), e.getTrigger());

        // 生成行为与效果
        if (e.trigger != null) {
            List<Behavior> heroBehaviors = new ArrayList<>();
            List<Behavior> otherBehaviors = new ArrayList<>();

            for (Behavior behavior : battle.getBattleData().getBehaviors()) {
                if (behavior.getOwner() != e.trigger) {
                    otherBehaviors.add(behavior);
                } else {
                    heroBehaviors.add(behavior);
                }
            }

            // 非自己的行为
            triggerEventCore(e, otherBehaviors);
            // 自己的行为
            triggerEventCore(e, heroBehaviors);
        } else {
            triggerEventCore(e, battle.getBattleData().getBehaviors());
        }

        // 记录录像信息
        battle.getRecorder().recordBhv(activeEventBhvs);
        activeEventBhvs.clear();

        // 处理效果
        battle.getEffectProcessor().run(e);
        getBhvTarget().clear();
        battle.onBehaviorOver();
    }

    // 根据排序 优先触发不需要跟随的行为
    // 不需要跟随的行为会产生目标，供需要跟随的行为使用
    private void triggerEventCore(Event e, List<Behavior> bhvs) {
        if (bhvs == null || bhvs.size() == 0) {
            return;
        }

        // 行为触发优先级排序
//        bhvs.sort(new Comparator<Behavior>() {
//            @Override
//            public int compare(Behavior o1, Behavior o2) {
//                return o2.getMould().getSort() - o1.getMould().getSort();
//            }
//        });

        List<Behavior> lowerBhvs = new ArrayList<>();

        // 先触发不需要跟随某行为目标的行为
        for (Behavior bhv : bhvs) {
            Integer bhvId = bhv.getMould().getTargetFollowBehaviorId();
            if (bhvId != null && bhvId > 0) {
                lowerBhvs.add(bhv);
            } else {
                bhv.onEvent(e);
            }
        }

        // 需要跟随某行为目标的行为，延后处理
        for (Behavior bhv : lowerBhvs) {
            bhv.onEvent(e);
        }
    }
}
